package org.springblade.modules.notice.core.channel;

import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson2.JSON;
import com.google.common.base.Throwables;
import lombok.extern.slf4j.Slf4j;
import org.springblade.common.utils.message.MessageCenterUtils;
import org.springblade.core.tool.utils.Func;
import org.springblade.modules.notice.core.receiver.PushObjectFactory;
import org.springblade.modules.notice.core.var.VariableParse;
import org.springblade.modules.notice.entity.MiddleMessageTemplateVariables;
import org.springblade.modules.notice.enums.BusinessType;
import org.springblade.modules.notice.enums.ChannelType;
import org.springblade.modules.notice.enums.placeholder.VariableEnum;
import org.springblade.modules.notice.service.IMiddleMessageTemplateService;
import org.springblade.modules.notice.utils.ContentHolderUtil;
import org.springblade.modules.notice.utils.PushIdTypeUtil;
import org.springblade.modules.notice.utils.VariableUtil;
import org.springblade.modules.notice.vo.MiddleMessageTemplateDetailVO;
import org.springblade.modules.notice.vo.NoticeTask;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * @Author ysq
 * @Date 2024/11/26
 * @Description 通知抽象处理器
 */
@Slf4j
public abstract class BaseNoticeHandler implements NoticeHandler {

	/**
	 * 对应渠道
	 * 子类初始化时需指定
	 * @see ChannelType
	 */
	protected Integer channelTypeCode;
	@Resource
	private NoticeHandlerFactory noticeHandlerFactory;
	@Resource
	private IMiddleMessageTemplateService middleMessageTemplateService;
	@Resource
	private VariableParse variableParse;
	@Resource
	protected PushObjectFactory pushObjectFactory;
	@Resource
	protected MessageCenterUtils messageCenter;

	@PostConstruct
	private void init() {
		noticeHandlerFactory.register(channelTypeCode, this);
	}

	/**
	 * 各子类消息处理逻辑
	 * @param task
	 * @throws Exception
	 */
	public abstract void handle(NoticeTask task) throws Exception;

	@Override
	public void doHandle(NoticeTask task) {
		try {
			MiddleMessageTemplateDetailVO templateDetail = middleMessageTemplateService.detailById(task.getMsgTemplateId());
			if (Func.isNull(templateDetail)) {
				log.warn("推送通知失败，未获取到消息模板，param: {}", JSONObject.toJSONString(task));
				return;
			}
			Map<String, String> templateVarMap = parseContent(templateDetail, task.getBizId(), task.getExtra());
			// 排除飞书机器人没有接收者
			if (task.getChannelType() != ChannelType.FEI_SHU_ROBOT.getCode()) {
				if (Func.isBlank(task.getPushType())) {
					log.warn("推送通知失败，未获取到推送类型，param: {}", JSONObject.toJSONString(task));
					return;
				}
				String pushObject = parsePushObject(task.getPushType(), templateDetail.getClientType(), task.getBizId());
				if (Func.isBlank(pushObject)) {
					log.warn("推送通知失败，未获取到接收人，param: {}", JSONObject.toJSONString(task));
					return;
				}
				task.setReceiver(pushObject);
			}

			task.setMiddlePlatformTemplateId(templateDetail.getMiddlePlatformTemplateId());
			task.setTemplateVariables(templateVarMap);
			task.setClientType(templateDetail.getClientType());
			handle(task);
		} catch (Exception e) {
			log.error("推送通知失败#handler fail:{},param:{}",
				Throwables.getStackTraceAsString(e), JSON.toJSONString(task));
		}
	}

	/**
	 * 内容解析
	 */
	private Map<String, String> parseContent(MiddleMessageTemplateDetailVO templateDetail, Long bizId, Map<String, String> extra) {
		// 模板变量
		Map<String, String> templateVarMap = new HashMap<>(8);
		// 解析变量结果
		Map<String, String> varValueMap = new HashMap<>(8);
		// 获取业务变量枚举类
		Class<? extends VariableEnum> variableEnumClass = BusinessType.getVariableEnumClassByCode(templateDetail.getBusinessType());

		// 合并两个列表
		List<List<MiddleMessageTemplateVariables>> combinedList = Stream.concat(templateDetail.getTitleList().stream(), templateDetail.getContentList().stream())
			.collect(Collectors.toList());
		// 获取内容的所有变量code对应sql
		Set<String> varSqlSet = combinedList.stream().flatMap(list -> list.stream().filter(t -> t.getVariableInputType() == 2)
			.map(t -> VariableUtil.getSqlByCode(Integer.valueOf(t.getVariableValue()), variableEnumClass))).collect(Collectors.toSet());
		// // url变量处理
		if (Func.isNotBlank(templateDetail.getSkipUrl())) {
			Set<String> urlVars = VariableUtil.extractVariables(templateDetail.getSkipUrl());
			for (String urlVar : urlVars) {
				String urlSql = VariableUtil.getSqlByVar(urlVar, variableEnumClass);
				if (Func.isBlank(urlSql)) {
					varValueMap.put(urlVar, "-");
				} else {
					varSqlSet.add(urlSql);
				}
			}
		}

		// 解析变量
		varValueMap.putAll(variableParse.parse(bizId, varSqlSet));
		for (List<MiddleMessageTemplateVariables> contentVar : combinedList) {
			String content = contentVar.stream().sorted(Comparator.comparing(t -> t.getColumnSort()))
				.map(t -> {
					if (t.getVariableInputType() == 1) {
						// 文本
						String text = t.getVariableValue();
						// 针对文本中包含变量处理
						Set<String> textVars = VariableUtil.extractVariables(text);
						if (Func.isNotEmpty(textVars)) {
							for (String textVar : textVars) {
								if (extra.containsKey(textVar)) {
									text = text.replace("${" + textVar + "}", extra.get(textVar));
								}
							}
						}
						return text;
					} else {
						// 变量
						String var = VariableUtil.getVarByCode(Integer.valueOf(t.getVariableValue()), variableEnumClass);
						return varValueMap.getOrDefault(var, "-");
					}
				}).collect(Collectors.joining());
			// 提取${var}变量名
			String varName;
			if (ChannelType.OFFICIAL_ACCOUNT.getCode().equals(templateDetail.getChannelType())) {
				varName = VariableUtil.extractVariableWx(contentVar.get(0).getVariableName());
			} else {
				varName = VariableUtil.extractVariable(contentVar.get(0).getVariableName());
			}
			if (Func.isNotBlank(varName)) {
				templateVarMap.put(varName, content);
			}
		}

		// 其它模板变量
		if (Func.isNotBlank(templateDetail.getSkipUrl())) {
			templateVarMap.put("url", ContentHolderUtil.replacePlaceHolder(templateDetail.getSkipUrl(), varValueMap));
		}
		if (Func.isNotBlank(templateDetail.getIconUrl())) {
			templateVarMap.put("iconUrl", templateDetail.getIconUrl());
		}
		if (Func.isNotBlank(templateDetail.getSignName())) {
			templateVarMap.put("signName", templateDetail.getSignName());
		}
		if (Func.isNotBlank(templateDetail.getSound())) {
			templateVarMap.put("sound", templateDetail.getSound());
		}
		// 额外变量
		if (Func.isNotEmpty(extra)) {
			templateVarMap.putAll(extra);
		}

		return templateVarMap;
	}

	/**
	 * 推送对象解析
	 * @param pushType
	 * @param clientType
	 * @param bizId
	 * @return
	 */
	private String parsePushObject(String pushType, Integer clientType, Long bizId) {
		Set<String> allReceivers = new LinkedHashSet<>(8);
		String idField = PushIdTypeUtil.getPushIdField(channelTypeCode, clientType);
		String[] pushTypeArr = pushType.split(",");
		for (String pushObject : pushTypeArr) {
			// 获取推送对象
			Set<String> receivers = pushObjectFactory.getHandler(Integer.valueOf(pushObject))
				.getPushReceivers(bizId, idField);
			if (Func.isNotEmpty(receivers)) {
				allReceivers.addAll(receivers);
			}
		}

		return allReceivers.stream().collect(Collectors.joining(","));
	}

}
